#include "common.h"
#include "console.h"
#include "commandcontroller.h"
#include "insertcontroller.h"
#include "linecontroller.h"

extern const int commandMode;
extern const int insertMode;
extern const int lineMode;

Console::Console(): activeController(0), document(0)
{
	this->controllers[commandMode] = new CommandController(this);
	this->controllers[insertMode] = new InsertController(this);
	this->controllers[lineMode] = new LineController(this);

	this->setController(this->controllers[commandMode]);

	this->initialize();
}

Console::~Console()
{
	delete this->controllers[commandMode];
	delete this->controllers[insertMode];
	delete this->controllers[lineMode];

	if (document)
		delete document;
}

void Console::initialize()
{
	window = initscr();
	this->status = new Statusbar(this->window);
	noecho();
	cbreak();
	keypad(window, true);
}

void Console::start(Argument *arg)
{
	chtype message = 0;
	
	if (arg)
	{
		this->setController(this->controllers[arg->getMode()]);
		if (arg->getFileName())
		{
			this->document->loadFile(arg->getFileName());
		}
	}
	
	/// This is a little trick, provent the disappear of the content after getch()
	nodelay(this->window, TRUE);
	getch();
	nodelay(this->window, FALSE);
	this->update();
	//////////////////////////////////////////////////////////////////////////////
	
	while (!this->isQuitMessage(message = this->getMessage()))
	{
		this->activeController->processMessage(message);
	}
	this->postQuite();
}

chtype Console::getMessage()
{
	chtype ch = getch();
	return ch;
}

bool Console::isQuitMessage(chtype message)
{
	if (message == 331)
		return true;
	return false;
}

bool Console::update()
{
	status->update(this->document->getPosLine(), this->document->getPosColumn());
	if (is_wintouched(this->document->getBufferWindow()))
	{
		touchwin(this->document->getBufferWindow());
	}
	wmove(this->document->getBufferWindow(), this->document->getPosLine(), this->document->getPosColumn());
	prefresh(this->document->getBufferWindow(),
			 this->document->getOffsetLine(), this->document->getOffsetColumn(),
			 0, 0, LINES - 2, COLS -1);
	return true;
}

void Console::postQuite()
{
	nocbreak();
	echo();
	endwin();
	exit(0);
}

Controller *Console::getInsertController()
{

	return this->controllers[insertMode];
}
Controller *Console::getCommandController()
{
	return this->controllers[commandMode];
}
Controller *Console::getLineController()
{
	return this->controllers[lineMode];
}

void Console::setController(Controller *controller)
{
	if (controller != this->activeController)
	{
		this->activeController = controller;
	}
	
	if (this->status)
	{
		this->status->changeMode(this->activeController->getMode());
		if (this->activeController->getMode() == lineMode)
		{
			this->status->getFocus(true);
			this->activeController->processMessage(':');	
		}
	}
	nodelay(this->window, TRUE);
	getch();
	nodelay(this->window, FALSE);	
}

WINDOW *Console::getWindow()
{
	return this->window;
}

Statusbar *Console::getStatusbar()
{
	return this->status;
}

void Console::bindDocument(Document *doc)
{
	if (this->document)
		delete this->document;
	this->document = doc;
}
